Some of you may recall that I wrote something about hashing various things into tcp_iss, things like network packets and inodes read from disk. Someone wrote to me privately and said > The basic problem is you want an absolute minimum cpu overhead per > packet, granted this isn't as important today as it was in the time > the sun3/50's were popular on the net. My reaction to this is basically that I'd rather have a slower machine that resists attacks than a fast one that gets broken wide open, but it is a valid point. Here's something I concocted for sun4c machines under SunOS 4.1.2; I believe it should work for any 4.1.x system, possibly with minor tweaks. It treats tcp_iss as a CRC accumulator into which it hashes every IP output packet. This is perhaps not as strong as it might be, but it's a hell of a lot better than what we used to have, and if the machine is at all busy on the network the attacker faces essentially random sequence numbers. (Perhaps I should also call uniqtime and hash that in too.) It does cost some cpu cycles for each output packet, it's true. Nobody has to run it. This is designed to be dropped into some two-level directory under /sys. I use /sys/local/OBJ; you can move it anywhere you like by changing the path in the Makefile that fetches ip_output out of the OBJ directory. You will need to do this anyway if you're building for other than sun4c kernel architecture. der Mouse mouse@collatz.mcrcim.mcgill.edu Legalisms: As its sole author, I place all this code - including the "patchsym" auxiliary program - into the public domain. Anyone may use it for any purpose...though I would appreciate credit where it's due. I make no promises about its worth for any purpose; the decision and the risk are all yours. It's free, and you get what you pay for. #! /bin/sh # # Shar: Shell Archiver # # This archive created Tue Jan 24 14:37:29 1995 # Run this through sh to create: # Makefile # patch.s # patchsym.c # crc.c echo x - Makefile \(571 characters\) sed 's/^X//' > Makefile << \EOF XASFLAGS = -P XCFLAGS = -O X Xip_output.o: ip_output-sympatch.o patch.o crc.o X ld -x -r -o ip_output.o ip_output-sympatch.o patch.o crc.o X Xip_output-sympatch.o: ip_output-dist.o patchsym X cp ip_output-dist.o _.o X ./patchsym _.o _ip_output _ip_output_wrapped X mv _.o ip_output-sympatch.o X Xip_output-dist.o: ../../sun4c/OBJ/ip_output.o X cp ../../sun4c/OBJ/ip_output.o ip_output-dist.o X Xpatch.o: patch.s X $(AS) $(ASFLAGS) patch.s -o patch.o X Xcrc.o: crc.c X $(CC) $(CFLAGS) -c crc.c X Xpatchsym: patchsym.c X $(CC) -o patchsym patchsym.c X Xclean: X @touch _.o X rm -f *.o patchsym core EOF if test 571 -ne "`wc -c Makefile`" then echo shar: error transmitting Makefile \(should have been 571 characters\) fi echo x - patch.s \(234 characters\) sed 's/^X//' > patch.s << \EOF X#include <sparc/asm_linkage.h> X X .global _ip_output_wrapped X .global _ip_output X .global _corrupt_iss X X .seg "text" X_ip_output: X save %sp,-SA(MINFRAME),%sp X call _corrupt_iss X mov %i0,%o0 X set _ip_output_wrapped,%o0 X jmp %o0 X restore EOF if test 234 -ne "`wc -c patch.s`" then echo shar: error transmitting patch.s \(should have been 234 characters\) fi echo x - patchsym.c \(3670 characters\) sed 's/^X//' > patchsym.c << \EOF X/* X * patchsym a.out old new [old new [old new ... ]] X * X * Modifies the given a.out in-place to change symbol names as given on the X * command line. X */ X X#include <stdio.h> X#include <a.out.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <unistd.h> X#include <fcntl.h> X X/*extern*/ char **argvec; X Xcaddr_t sbrk(); X#define SBRKERR ((caddr_t)-1) X Xint aout_fd; Xstruct stat stb; Xstruct exec hdr; Xint symsize; Xchar *symtbl; Xint strsize; Xchar *strtbl; X Xgrowstrings(nb) Xint nb; X{ X char *new; X X new = sbrk(nb); X if (new != strtbl+strsize) X { sbrk(strsize); X bcopy(strtbl,new,strsize); X } X strsize += nb; X} X Xmain(ac,av) Xint ac; Xchar **av; X{ X int nchg; X int i; X int j; X int l; X struct nlist *sym; X char *name; X X argvec = av; X if ((ac & 1) || (ac < 4)) X { fprintf(stderr,"Usage: %s a.out-file old new [old new [old new ... ]]\n",argvec[0]); X exit(1); X } X nchg = (ac / 2) - 1; X#define OLDNAME(i) av[(((i)*2)+2)] X#define NEWNAME(i) av[(((i)*2)+3)] X/* X for (i=0;i<nchg;i++) X { if (strlen(OLDNAME(i)) != strlen(NEWNAME(i))) X { fprintf(stderr,"%s: old and new symbol names must be the same length (%s->%s)\n",argvec[0],OLDNAME(i),NEWNAME(i)); X exit(1); X } X } X*/ X aout_fd = open(av[1],O_RDWR,0); X if (aout_fd < 0) X { fprintf(stderr,"%s: can't open ",argvec[0]); X perror(av[1]); X exit(1); X } X if (fstat(aout_fd,&stb) < 0) X { fprintf(stderr,"%s: can't get size of %s\n",argvec[0],av[1]); X exit(1); X } X if (read(aout_fd,(char *)&hdr,sizeof(hdr)) != sizeof(hdr)) X { fprintf(stderr,"%s: can't read a.out header from %s\n",argvec[0],av[1]); X exit(1); X } X if (N_BADMAG(hdr)) X { fprintf(stderr,"%s: %s: bad magic number\n",argvec[0],av[1]); X exit(1); X } X symsize = hdr.a_syms / sizeof(struct nlist); X symtbl = sbrk(symsize*sizeof(struct nlist)); X if (symtbl == SBRKERR) X { fprintf(stderr,"%s: can't allocate %lu bytes of memory for symbol table\n",symsize*sizeof(struct nlist)); X exit(1); X } X strsize = stb.st_size - N_STROFF(hdr); X strtbl = sbrk(strsize+1); X if (strtbl == SBRKERR) X { fprintf(stderr,"%s: can't allocate %d bytes of memory for string table\n",strsize); X exit(1); X } X if ( (lseek(aout_fd,N_SYMOFF(hdr),SEEK_SET) < 0) || X (read(aout_fd,symtbl,hdr.a_syms) != hdr.a_syms) ) X { fprintf(stderr,"%s: can't read symbol table from %s\n",argvec[0],av[1]); X exit(1); X } X if ( (lseek(aout_fd,N_STROFF(hdr),SEEK_SET) < 0) || X (read(aout_fd,strtbl,strsize) != strsize) ) X { fprintf(stderr,"%s: can't read string table from %s\n",argvec[0],av[1]); X exit(1); X } X if (strtbl[strsize-1] != '\0') X { growstrings(1); X strtbl[strsize-1] = '\0'; X } X for (i=0;i<symsize;i++) X { sym = ((struct nlist *) symtbl) + i; X if ((sym->n_un.n_strx <= 0) || (sym->n_un.n_strx >= strsize)) continue; X name = strtbl + sym->n_un.n_strx; X for (j=0;j<nchg;j++) X { if (!strcmp(name,OLDNAME(j))) break; X } X if (j < nchg) X { l = strlen(NEWNAME(j)); X if (l <= strlen(OLDNAME(j))) X { strcpy(strtbl+sym->n_un.n_strx,NEWNAME(j)); X } X else X { growstrings(l+1); X bcopy(NEWNAME(j),&strtbl[strsize-l-1],l+1); X sym->n_un.n_strx = strsize - l - 1; X } X } X } X if ( (lseek(aout_fd,N_SYMOFF(hdr),SEEK_SET) < 0) || X (write(aout_fd,(char *)symtbl,symsize*sizeof(struct nlist)) != symsize*sizeof(struct nlist)) ) X { fprintf(stderr,"%s: error writing new symbol table, result is probably mangled\n",argvec[0]); X exit(1); X } X *(int *)strtbl = strsize; X if ( (lseek(aout_fd,N_STROFF(hdr),SEEK_SET) < 0) || X (write(aout_fd,(char *)strtbl,strsize) != strsize) ) X { fprintf(stderr,"%s: error writing new string table, result is probably mangled\n",argvec[0]); X exit(1); X } X exit(0); X} EOF if test 3670 -ne "`wc -c patchsym.c`" then echo shar: error transmitting patchsym.c \(should have been 3670 characters\) fi echo x - crc.c \(766 characters\) sed 's/^X//' > crc.c << \EOF X#include <sys/types.h> X#include <sys/mbuf.h> X Xextern unsigned long int tcp_iss; X X#define POLY 0xedb88320 Xstatic unsigned long int crctable[256]; X Xstatic void make_crctable() X{ X register unsigned long int acc; X register unsigned long int n; X register int i; X X for (n=0;n<256;n++) X { acc = n; X for (i=0;i<8;i++) X { acc = (acc & 1) ? ((acc >> 1) ^ POLY) : (acc >> 1); X } X crctable[n] = acc; X } X} X Xvoid corrupt_iss(m) Xregister struct mbuf *m; X{ X register unsigned long int acc; X register unsigned char *dp; X register int n; X X if (crctable[128] != POLY) make_crctable(); X acc = tcp_iss; X for (;m;m=m->m_next) X { dp = mtod(m,unsigned char *); X for (n=m->m_len;n>0;n--) X { acc = (acc >> 8) ^ crctable[(acc&0xff)^*dp++]; X } X } X tcp_iss = acc; X} EOF if test 766 -ne "`wc -c crc.c`" then echo shar: error transmitting crc.c \(should have been 766 characters\) fi exit 0 # end of shell archive